/*
 * cpu.cpp
 *
 *  Created on: Feb 1, 2012
 *      Author: dgdiniz
 */

#include <iostream>
#include <stdio.h>
#include "cpu.hpp"

using namespace std;


void cpu::reset(){
	z80_reset();

	for (int i=0; i<4000; i++) Memory[i]=0;

	programSize = 0;
	runningProgram = false;

	regs.AF = 0x0;
	regs.BC = 0x0;
	regs.DE = 0x0;
	regs.HL = 0x0;

	regs.IX = regs.IY = 0x0;

	regs.pc = 0x0;
	regs.sp = 0x0;

	regs.s = regs.ss = 0x0;

	for (int i=0; i<8; i++) regs.rs[i] = 0x0;
}


u8 cpu::read8(u16 address, int cycles){
#ifdef Z80_TEST
	OpTCycles += cycles;
	OpMCycles++;
#endif
	return Memory[address];
}

void cpu::write8(u16 address, u8 data, int cycles){
#ifdef Z80_TEST
	OpTCycles += cycles;
	OpMCycles++;
#endif
	Memory[address] = data;
}

void cpu::sync(int cycles)
{
#ifdef Z80_TEST
	OpTCycles += cycles;
	OpMCycles++;
#endif
}

void cpu::retCallback(int cycles){
	if (regs.pc >= programSize)
	{
		runningProgram = false;
	}
}


void cpu::test_registers(){

	*regs.r[0] = 1;

	cout << "\n\nTesting Basic Functions. Testing r[]  - ";
	if (regs.BC == 0x100 && regs.B == 0x1 && regs.C == 0x0)
	{
		cout << "OK" << endl;
	}
	else
	{
		cout << "ERROR" << endl;
	}

	z80_reset();

	regs.BC = 2;

	cout << "Testing Basic Functions. Testing pair - ";
	if (regs.BC == 0x2 && regs.B == 0x0 && regs.C == 0x2)
	{
		cout << "OK" << endl;
	}
	else
	{
		cout << "ERROR" << endl;
	}


	regs.Flags.h = 1;

	cout << "Testing Flags                         - ";
	if (regs.F == 0x10 && regs.Flags.h == 0x1)
	{
		cout << "OK" << endl;
	}
	else
	{
		cout << "ERROR" << endl;
	}
}


u32 cpu::run_program(const char *programPath){

	FILE * program;
	size_t result;

	reset();

	regs.E = 4;

	program = fopen(programPath, "rb");

	if (program)
	{
		// obtain file size:
		fseek (program , 0 , SEEK_END);
		programSize = ftell (program);
		rewind (program);

		//TODO: the file size must be less than 4000 bytes. Check this.

		// copy the file into the buffer:
		result = fread (Memory,1,programSize,program);

		if (result != programSize)
		{
			//error
		}

		fclose (program); //We don't need this anymore hehe

		runningProgram = true; //starting the program. We need to set this
		while (runningProgram)
		{
			z80_step();
		}
	}

	return 0;
}


u32 cpu::load_program(const char *programPath){

	FILE * program;
	size_t result;

	reset();

	program = fopen(programPath, "rb");

	if (program)
	{
		// obtain file size:
		fseek (program , 0 , SEEK_END);
		programSize = ftell (program);
		rewind (program);

		//TODO: the file size must be less than 4000 bytes. Check this.

		// copy the file into the buffer:
		result = fread (Memory,1,programSize,program);

		if (result != programSize)
		{
			//error
		}

		fclose (program); //We don't need this anymore hehe
	}

	return 0;
}


void cpu::memoryDump(u16 start, u16 size)
{
	cout << "Memory Dump Starting at Address "<< hex << start << endl << endl;

	if ((start+size) > 4087)
	{
		cout << "We cannot dump this region of Memory!"<< endl;
		return;
	}

	for (int i=0; i<size; i+=8) //TODO: fix this thing. For a full memory this will fail.
	{
		cout << hex << (int) Memory[start+i] << (int) Memory[start+i+1] << (int) Memory[start+2] << (int) Memory[start+i+3] ;
		cout << " " << hex << (int) Memory[start+i+4] << (int) Memory[start+i+5] << (int) Memory[start+i+6] << (int) Memory[start+i+7] << endl ;

	}
}

void cpu::registersDump()
{
	cout << "Registers Dump "<< endl << endl;

	cout << "A: " << hex << (int) regs.A << "  ---  ";
	cout << "B: " << hex << (int) regs.B << "  ---  ";
	cout << "C: " << hex << (int) regs.C << "  ---  ";
	cout << "D: " << hex << (int) regs.D << "  ---  ";
	cout << "E: " << hex << (int) regs.E << "  ---  ";
	cout << "H: " << hex << (int) regs.H << "  ---  ";
	cout << "L: " << hex << (int) regs.L << "  ---  " << endl << endl;

	cout << "AF: " << hex << (int) regs.AF << "  ---  ";
	cout << "BC: " << hex << (int) regs.BC << "  ---  ";
	cout << "DE: " << hex << (int) regs.DE << "  ---  ";
	cout << "HL: " << hex << (int) regs.HL << "  ---  " << endl << endl;

	cout << "PC: " << hex << (int) regs.pc << "  ---  ";
	cout << "SP: " << hex << (int) regs.sp << "  ---  " << endl << endl;
}



void cpu::test_processor(){

	run_program("/home/dgdiniz/Downloads/z80asm/ADD/add1");
	registersDump();
}

void cpu::test_memory(){

	load_program("/home/dgdiniz/Downloads/z80asm/a.bin");
	memoryDump(0, 32);
}


